TemplateCompiler.php

<?php

namespace Phad;

/**
 * Template Compiler for compiling PHP Scripts from a template, a view, and an array of arguments to fill in the template
 */
class TemplateCompiler {

    /**
     * @param $item the Phad view you want to compile
     * @param $template the template you want to compile it with
     * @return string Fully compiled view 
     */
    public function compile(string $item, string $template): string {
        $doc = new \Taeluf\PHTML($item);
        $parser = new \Phad\DomParser();

        // needs fixing for multiple items
        $items = $parser->parse_doc($doc);

        return $doc.'';
    }

    /**
     * Process all `/* @@if.start.name *\/` placeholders. Modifies `$template` and `$template_fillers`
     *
     * Replaces `@@if1.start.whatever` with `@@start.whatever` and adds `@@__if1_#` before `if()`.
     * Adds `__if1_#` entries to `$template_fillers`
     *
     * @param &$template the template to parse and modify
     * @param &$template_fillers variable to put special template fillers into. Also should contain keys for each of your `@@if1.start.whatever` statements indicating `true/false` for displaying `whatever` or not
     */
    public function precompile_ifs(string &$template, ?array &$template_fillers){

        $reg = '/\/\*\*? ?\@\@if([0-9]{0,2}).start\.([a-zA-Z\_0-9]+) ?\*\//';
        preg_match_all($reg, $template, $matches);

        $params = [];

        $template_fillers_index = 0;
        $ifs_activated = [];
        foreach ($matches[0] as $index=>$full_match){
            $if_index = $matches[1][$index];
            $key = $matches[2][$index];
            $ifs[$if_index][$key] = $full_match;
            $start_pos = strpos($template, $full_match);
            $after_start_pos = $start_pos + strlen($full_match);
            $if_pos = strpos($template, 'if', $after_start_pos);

            $ifs_key = '__ifs'.$if_index.'_'.$index;
            $template = 
                substr($template,0,$start_pos)
                    . '/* @@start.'.$key.' */'
                    .substr($template,$after_start_pos, $if_pos - $after_start_pos)
                    .'/* @@'.$ifs_key.' */'
                .substr($template,$if_pos);
                ;
            // $params[$key] = 'else';

            if (isset($template_fillers[$key])&&$template_fillers[$key]===true){
                $replacement = 'else';
                if ($template_fillers_index==0)$replacement = '';
                $template_fillers[$ifs_key] = $replacement;
                $template_fillers_index++;
                $ifs_activated[$if_index] = $template_fillers_index;
            }
        }

        foreach ($ifs_activated as $if_index=>$num_ifs){
            $template_fillers['else'.$if_index] = 'else ';
        }

    }

    /**
     * Fill a template (final template compilation step)
     *
     * @param $template the template code to fill in
     * @param $template_args args found inside the template. @see(get_template_args())
     * @param $template_fillers `key=>value` array of strings to insert into `$template` in place of `$template_args[$key]`
     *
     * @return filled-in template 
     */
    public function fill_template(string $template, array $template_args, array $template_fillers){

        // sort from largest placeholder value to smallest
        uksort($template_args,
            function($ka,$kb) use ($template_args){
                $al = strlen($template_args[$ka]);
                $bl = strlen($template_args[$kb]);

                return $bl-$al;
            }
        );

        // get replacement value from $template_fillers, then the placeholder in the template
        foreach ($template_args as $key=>$placeholder){
            $replacement = $template_fillers[$key]??'';
            // if ($replacement===true)continue;
            if ($replacement===false)$replacement = '';
            // var_dump($replacement);
            // var_dump("Placeholder:".$placeholder);
            $template = str_replace($placeholder, $replacement, $template);
        }

        return $template;
    }

    /**
     * Get array of arguments found inside the template (which will later be replaced)
     *
     * @param $template the template to inspect
     * @param &$template_fillers `key=>value` array for filling the template. Will be modified.
     *
     * @return `key=>value` array of arguments in the template where `key` is the argument name and `value` is the placeholder string written in the template
     */
    public function get_template_args(string $template, ?array &$template_fillers){
        
        $comment_args = $this->get_comment_args($template);
        $var_args = $this->get_var_args($template);
        $start_end = $this->get_start_end_args($template, $template_fillers);

        $params = array_merge($comment_args, $var_args, $start_end);

        
        return $params;
    }

    /**
     *  Get args like `/* @@start.name *\/` (and @@end) and modify the template & template fillers as needed
     *
     *  @param $template the template to process
     *  @param &$template_fillers `key=>value` array ... should contain `true/false` values for each key of `@@start.key`
     *
     *  @return array of template args for `@@start/@@end` pairs
     */
    public function get_start_end_args(string $template, ?array &$template_fillers){
        # looks like /* @@param */
        $reg = '/\/\*\*? ?\@\@start\.([a-zA-Z\_0-9]+) ?\*\//';
        preg_match_all($reg, $template, $matches);

        foreach ($matches[0] as $index=>$full_match){
            $key = $matches[1][$index];

            $start_pos_before = strpos($template, $full_match);
            $start_pos_after = $start_pos_before + strlen($full_match);


            $end = str_replace('start','end', $full_match);
            $end_pos_before = strpos($template, $end);
            $end_pos_after = $end_pos_before + strlen($end);
            

            $full_string_length = $end_pos_after - $start_pos_before;
            $full_string = substr($template, $start_pos_before, $full_string_length);

            $params[$key] = $full_string;

            if (isset($template_fillers[$key])&&$template_fillers[$key]===true){
                $template_fillers[$key] = substr($template,$start_pos_after, $end_pos_before - $start_pos_after);
            } else if (!isset($template_fillers[$key])){
                $template_fillers[$key] = '';
            }
        }

        // print_r($params);
        // exit;

        return $params??[];
    }

    /**
     * Get template args like `@$$Arg`
     * @param $template the template to process
     * @rereturn `key=>value` array like `['Arg'=>'@$$Arg']`
     */
    public function get_var_args(string $template){
        $reg = '/\@\$\$([a-zA-Z\_0-9]+)/';
        preg_match_all($reg, $template, $matches);
        $params = array_combine($matches[1], $matches[0]);
        return $params;
    }

    /**
     * Get template args like /* @@arg *\/    # minus the backslash
     * @param $template the template to process
     * @return `key=>value` array like `['Arg'=>'/* @@arg *\/']`
     */
    public function get_comment_args(string $template){
        # looks like /* @@param */
        $reg = '/\/\*\*? ?\@\@([a-zA-Z\_0-9]+) ?\*\//';
        preg_match_all($reg, $template, $matches);
        $params = array_combine($matches[1], $matches[0]);
        return $params;
    }


}